# -*- coding: utf-8 -*-
"""
Created on Sat Apr 26 08:49:48 2025

@author: mulla
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import iirnotch, filtfilt
import pandas as pd
import tkinter as tk
from tkinter import filedialog, messagebox
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

class PPGFilterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("PPG Signal Notch Filter GUI")

        # Sampling frequency
        self.Fs = 125

        # Create UI components
        self.create_widgets()

    def create_widgets(self):
        # Button to load CSV file
        self.load_btn = tk.Button(self.root, text="Load PPG CSV", command=self.load_data)
        self.load_btn.pack(pady=5)

        # Button to run filtering and plot
        self.filter_btn = tk.Button(self.root, text="Filter Signal", command=self.filter_signal, state=tk.DISABLED)
        self.filter_btn.pack(pady=5)

        # Frame to hold plots
        self.plot_frame = tk.Frame(self.root)
        self.plot_frame.pack(fill=tk.BOTH, expand=True)

    def load_data(self):
        file_path = filedialog.askopenfilename(
            filetypes=[("CSV files", "*.csv"), ("All files", "*.*")]
        )
        if not file_path:
            return

        try:
            self.data = pd.read_csv(file_path, header=None).values.flatten()
            self.t = np.arange(len(self.data)) / self.Fs
            messagebox.showinfo("Success", f"Loaded data from {file_path}")
            self.filter_btn.config(state=tk.NORMAL)
        except Exception as e:
            messagebox.showerror("Error", f"Failed to load data: {e}")

    def filter_signal(self):
        # Add 60 Hz noise
        noise60 = 0.5 * np.sin(2 * np.pi * 60 * self.t)
        ppg_noisy = self.data + noise60

        # Design notch filter
        f0 = 60  # Frequency to remove
        Q = 30
        b, a = iirnotch(f0, Q, self.Fs)

        # Apply filter
        ppg_filtered = filtfilt(b, a, ppg_noisy)

        # Clear previous plots
        for widget in self.plot_frame.winfo_children():
            widget.destroy()

        # Create figure for plots
        fig, axs = plt.subplots(2, 2, figsize=(10, 6))

        # Time domain plots
        axs[0, 0].plot(self.t, ppg_noisy, 'r')
        axs[0, 0].set_title('PPG Signal with 60 Hz Noise')
        axs[0, 0].set_xlabel('Time (s)')
        axs[0, 0].set_ylabel('Amplitude')
        axs[0, 0].grid(True)

        axs[1, 0].plot(self.t, ppg_filtered, 'b')
        axs[1, 0].set_title('Filtered PPG Signal (60 Hz Removed)')
        axs[1, 0].set_xlabel('Time (s)')
        axs[1, 0].set_ylabel('Amplitude')
        axs[1, 0].grid(True)

        # Frequency domain analysis
        n = len(ppg_noisy)
        f = np.fft.fftfreq(n, 1/self.Fs)[:n//2]
        PPG_noisy_fft = np.abs(np.fft.fft(ppg_noisy))[:n//2]
        PPG_filt_fft = np.abs(np.fft.fft(ppg_filtered))[:n//2]

        axs[0, 1].plot(f, PPG_noisy_fft, 'r')
        axs[0, 1].set_xlim([0, 62.5])
        axs[0, 1].set_title('Frequency Domain - Noisy Signal')
        axs[0, 1].set_xlabel('Frequency (Hz)')
        axs[0, 1].set_ylabel('Magnitude')
        axs[0, 1].grid(True)

        axs[1, 1].plot(f, PPG_filt_fft, 'b')
        axs[1, 1].set_xlim([0, 62.5])
        axs[1, 1].set_title('Frequency Domain - Filtered Signal')
        axs[1, 1].set_xlabel('Frequency (Hz)')
        axs[1, 1].set_ylabel('Magnitude')
        axs[1, 1].grid(True)

        plt.tight_layout()

        # Embed the matplotlib figure in Tkinter
        canvas = FigureCanvasTkAgg(fig, master=self.plot_frame)
        canvas.draw()
        canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)

if __name__ == "__main__":
    root = tk.Tk()
    app = PPGFilterApp(root)
    root.geometry("900x700")
    root.mainloop()
